package com.san.simulation.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.san.simulation.api.PathResolver;
import com.san.simulation.model.api.Element;
import com.san.simulation.model.api.ElementType;
import com.san.simulation.model.api.Path;
import com.san.simulation.model.api.ProcessDefinition;

public class ActivitiPathResolver implements PathResolver {

	private PathResolverHelper helper = new PathResolverHelper();
	int levelCounter = 0;
	Map<String, Boolean> transitionVisited = new HashMap<String, Boolean>();
	String exclusiveId = null;

	public List<Path> resolvePath(ProcessDefinition definition) {

		if (definition == null) {
			throw new RuntimeException(
					"Process Definition must be set prior to invoking resolveProcessPath method");
		}

		Element activity = definition.getStartElement();

		resolvePathWithHelper(activity);

		List<Path> resolveProcessPaths = helper.getPaths();

		return resolveProcessPaths;
	}

	protected void resolvePathWithHelper(Element activity) {

		// validate the element before processing it
		// validator.validate(activity);

		// add given activity to parent activities since all of the paths will
		// contain that one

		if (helper.hasCurrentPath() && helper.getCurrentPath().getPathElements().contains(activity)) {

			helper.finalizePath();
			return;
		}

		helper.addParentElement(activity);
		levelCounter++;
		activity.setLevel(levelCounter);

		if (helper.hasCurrentPath()) {
			helper.addCurrentPathActivity(activity);
		}

		// process outgoing transitions if any
		if (activity.getOutgoingTransitions().size() > 0) {

			if (activity.getType().equals("exclusiveGateway")
					&& exclusiveId == null) {

				exclusiveId = activity.getId();

				for (Element tran : activity.getOutgoingTransitions()) {
					if (transitionVisited.get(tran.getId()) == null) {
						transitionVisited.put(tran.getId(), Boolean.FALSE);
					}
				}
			}

			for (Element tran : activity.getOutgoingTransitions()) {
				tran.setLevel(levelCounter);
				// check if currently processed activity is of a type that
				// causes to create new path
				if (helper.triggerNewPath(activity)) {
					helper.newPath();
				}
				// add every transition element to parent
				helper.addParentElement(tran);

				if (helper.hasCurrentPath()) {
					helper.addCurrentPathActivity(tran);
				}
				// call the method recursively

				// System.out.println(tran+" "+tran.getVisited());
				// if (transitionVisited.get(tran.getId())==null ||
				// !transitionVisited.get(tran.getId())) {
				// if (activity.getType().equals("exclusiveGateway")) {
				// transitionVisited.put(tran.getId(), Boolean.TRUE);
				// }
				// // helper.addVisitedPath(tran.getId());
				// // System.out.println(tran.getId());
				// System.out.println(transitionVisited+"-------------- "+tran.getId()+"-----"+transitionVisited.get(tran.getId()));
				// resolvePathWithHelper(tran.getDestination());
				// } else {
				//
				// helper.finalizePath();
				// }

				if (!activity.getType().equals("exclusiveGateway")) {

					resolvePathWithHelper(tran.getDestination());
				} else if (activity.getType().equals("exclusiveGateway")
						&& (transitionVisited.get(tran.getId()) == null || !transitionVisited
								.get(tran.getId()))) {
					/*System.out.println(transitionVisited + "--------"
							+ tran.getId());*/

					if (transitionVisited.containsKey(tran.getId())) {
						transitionVisited.put(tran.getId(), Boolean.TRUE);
					}
					/*System.out.println(transitionVisited + "--------"
							+ tran.getId());*/

					resolvePathWithHelper(tran.getDestination());

				} else {
					helper.finalizePath();
				}

			}
		} else {
			// no more outgoing transitions found, end of path
			helper.finalizePath();
		}
		// all elements processed for current level so remove it from parent
		// so they will not be included in another path
		helper.removeCurrentLevelFromParentElements(activity);
		levelCounter--;

	}

}
